package dimension.starry.gui.Particle;

import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.font.TextRenderer;
import net.minecraft.client.particle.Particle;
import net.minecraft.client.particle.ParticleTextureSheet;
import net.minecraft.client.render.Camera;
import net.minecraft.client.render.Tessellator;
import net.minecraft.client.render.VertexConsumer;
import net.minecraft.client.render.VertexConsumerProvider;
import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.client.world.ClientWorld;
import net.minecraft.entity.LivingEntity;
import net.minecraft.entity.damage.DamageSource;
import net.minecraft.nbt.visitor.NbtTextFormatter;
import net.minecraft.text.Text;
import net.minecraft.util.Formatting;

@Environment(EnvType.CLIENT)
public class DamageParticle extends Particle {

    private final String text;
    private float particleScale = 1.0f;

    protected DamageParticle(ClientWorld world, double x, double y, double z, String text) {
        super(world, x, y, z);
        maxAge = 20;
        this.velocityX = 0;
        this.velocityY = 0;
        this.velocityZ = 0;
        this.collidesWithWorld = false;
        this.text = text;
    }

    private static final Text CRITICAL_TEXT = Text.translatable("starry_dimension.gui.message.critical");

    public static void showParticle(
        LivingEntity livingEntity, DamageSource damageSource, float damage, boolean isCritical
    ) {
        if (MinecraftClient.getInstance().world != null && damage > 1 && livingEntity.getEntityWorld().isClient()) {
            String damageString =
                (double) damage % 1.0D == 0.0D ? String.format("%.0f", damage) : String.format("%.1f", damage);
            if (isCritical) {
                damageString = CRITICAL_TEXT.getString() + damageString;
            }
            double posX = livingEntity.getX();
            double posY = livingEntity.getBodyY(1.0D) + 0.24D;
            double posZ = livingEntity.getZ();
            DamageParticle damageParticle = new DamageParticle(MinecraftClient.getInstance().world, posX, posY, posZ,
                damageString
            );
            damageParticle.setColor(Formatting.RED.getColorValue() == null ? 16733525 : Formatting.RED.getColorValue());
            damageParticle.setSize(damageString.length() * 0.3f + 1);
            damageParticle.setMaxAge(20);
            MinecraftClient.getInstance().particleManager.addParticle(damageParticle);
        }
    }

    private static int getColorFromRGBA(float red, float green, float blue, float alpha) {
        return (int) (alpha * 255.0F) << 24 | (int) (red * 255.0F) << 16 | (int) (green * 255.0F) << 8 |
            (int) (blue * 255.0F);
    }

    public void setSize(float size) {
        this.particleScale = size;
    }

    public void setColor(int color) {
        this.red = (float) (color >> 16 & 255) / 255.0F;
        this.green = (float) (color >> 8 & 255) / 255.0F;
        this.blue = (float) (color & 255) / 255.0F;
    }

    @Override
    public void buildGeometry(VertexConsumer vertexConsumer, Camera camera, float partialTicks) {
        if (text != null && !text.isEmpty()) {
            TextRenderer textRenderer = MinecraftClient.getInstance().textRenderer;

            float particleX = (float) (
                this.prevPosX + (this.x - this.prevPosX) * (double) partialTicks - camera.getPos().getX()
            );
            float particleY = (float) (
                this.prevPosY + (this.y - this.prevPosY) * (double) partialTicks - camera.getPos().getY()
            );
            float particleZ = (float) (
                this.prevPosZ + (this.z - this.prevPosZ) * (double) partialTicks - camera.getPos().getZ()
            );
            float textX = (float) (-textRenderer.getWidth(text) / 2);
            float textY = 0.0F;
            int textColor = getColorFromRGBA(this.red, this.green, this.blue, this.alpha);
            int shadowColor = getColorFromRGBA(this.red * 0.314F, this.green * 0.314F, this.blue * 0.314F, this.alpha);

            if (this.alpha != 0.0F) {
                VertexConsumerProvider.Immediate vertexConsumerProvider = VertexConsumerProvider.immediate(
                    Tessellator.getInstance().getBuffer());
                MatrixStack matrixStack = new MatrixStack();
                matrixStack.push();
                matrixStack.translate(particleX, particleY, particleZ);
                matrixStack.multiply(camera.getRotation());
                matrixStack.scale(-0.024F, -0.024F, 0.024F);
                if (this.particleScale != 0.0D) {
                    matrixStack.scale(this.particleScale, this.particleScale, 1.0F);
                }

                matrixStack.translate(0.0D, 0.0D, 1.0D);
                textRenderer.draw(text, textX, textY, shadowColor, false, matrixStack.peek().getPositionMatrix(),
                    vertexConsumerProvider,
                    TextRenderer.TextLayerType.NORMAL, 0, 15728880
                );
                matrixStack.translate(0.0D, 0.0D, -2.0D);
                textRenderer.draw(text, textX, textY, textColor, false, matrixStack.peek().getPositionMatrix(),
                    vertexConsumerProvider,
                    TextRenderer.TextLayerType.NORMAL, 0, 15728880
                );
                matrixStack.translate(0.0D, 0.0D, 1.0D);
                matrixStack.pop();
                vertexConsumerProvider.draw();
            }
        }
    }

    @Override
    public ParticleTextureSheet getType() {
        return ParticleTextureSheet.CUSTOM;
    }
}
